---@class NChess.GameLogic : Base.GameLogic
---@field public room NChess.Room
local GameLogic = Fk.Base.GameLogic:subclass("NChess.GameLogic")

local Ch = require "packages.chess-games.nchess"

function GameLogic:run()
  table.shuffle(self.room.players)
  self:adjustSeats()
  self:assignRole()

  self:initBoard()

  self:action()
end

function GameLogic:assignRole()
  local room = self.room

  room:setPlayerProperty(room.players[1], "role", "white")
  room:setPlayerProperty(room.players[2], "role", "black")
end

---@param board integer[][]?
function GameLogic:initBoard(board)
  local room = self.room
  if board then
    room.board = board
  end

  room:syncBoard()
end

function GameLogic:turn(count)
  local room = self.room

  room:sendLog{
    type = "NChessTurnStart",
    arg = tostring(count)
  }

  for _, player in ipairs(room.players) do
    local color = player.role
    local board = room.board

    --先处理和棋请求
    room:askToArmistice(player)
   
    local movable = {} ---@type [integer, integer, integer][]
    for y, arr in ipairs(board) do
      for x, id in ipairs(arr) do
        local piece = Ch:getPieceById(id)
        if piece and piece:getColor() == color and piece:canMove(board, x, y) then
          table.insert(movable, { id, x, y })
        end
      end
    end

    if #movable == 0 then
      if Ch:isChecking(board, player.next.role) then
        room:sendLog{
          type = "#NChessOver",
          arg = player.next._splayer:getScreenName(),
          arg2 = player.next == "white" and "nchess_white" or "nchess_black",
          arg3 = player.next == "white" and tostring(count - 1) or tostring(count)
        }
        room:gameOver(player.next.role)
      else
        room:sendLog{
          type = "#NChessForceDraw",
          arg = player.next._splayer:getScreenName(),
          arg2 = player.next.role == "white" and "nchess_white" or "nchess_black",
        }
        room:gameOver(player.role .. "+" .. player.next.role)
      end
      return
    end

    local tmp = table.random(movable)
    local pieceId, fromX, fromY = tmp[1], tmp[2], tmp[3]
    local movableXY = {} ---@type [integer, integer][]
    local piece = Ch:getPieceById(pieceId)
    for y, arr in ipairs(board) do
      for x, _ in ipairs(arr) do
        local can_move, special_move = piece:canMoveTo(board, fromX, fromY, x, y)
        if can_move and not piece:willBeChecked(board, fromX, fromY, x, y) and
          (not special_move or -- 不是王车易位
            (not piece:willBeChecked(board, fromX, fromY, fromX, fromY) and -- 检查1.没有被将军; 2.王的易位路上没有被攻击
            not piece:willBeChecked(board, fromX, fromY, (5 + x) / 2, fromY))
          ) then
          table.insert(movableXY, { x, y })
        end
      end
    end
    local xy = table.random(movableXY)
    local default = {
      pieceId = pieceId,
      fromX = fromX,
      fromY = fromY,
      x = xy[1],
      y = xy[2],
    }

    local req = Request:new(player, "NChess.PlayChess")
    req:setData(player)
    req:setDefaultReply(player, default)
    -- req.timeout = 10000
    local result = req:getResult(player)

    local eatMark
    if room.board[result.y][result.x] ~= 0 then
      eatMark = true
    end
    local move = room:movePieceTo(result.pieceId, result.fromX, result.fromY, result.x, result.y)
    local annotation = Ch:translateMovement(result.pieceId, room.board, result.fromX, result.fromY, result.x, result.y, eatMark, move)

    room:sendLog{
      type = "#NChessMove",
      arg = color == "white" and "nchess_white" or "nchess_black",
      arg2 = annotation[1] .. " " .. annotation[2] .. "-->" .. annotation[3],
      arg3 = annotation[4]
    }
  end
end

function GameLogic:action()
  local room = self.room
  room:sendLog{
    type = "#NChessStart",
    arg = room.players[1]._splayer:getScreenName(),
    arg2 = room.players[2]._splayer:getScreenName(),
  }

  local i = 1
  while true do
    room:setBanner("RoundCount", i)
    room:doBroadcastNotify("NChess.UpdateRoundCount", i)
    self:turn(i)
    i = i + 1
  end
end

return GameLogic
